/*
 * @Author: your name
 * @Date: 2021-03-31 08:31:20
 * @LastEditTime: 2021-04-15 20:51:41
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \tower_defense\assets\scripts\game_scene\tower\cannon_bullet.ts
 */

import { UG } from "../../modules/ugame"
import { CannonBulletParams } from "../../game_data/tower_data/cannon_bullet_params";
import Enemy from "../enemy/enemy";
import { FrameAnim } from "../../common/frame_anim";
import { CannonTowerParams } from "../../game_data/tower_data/cannon_tower_params";

const { ccclass, property } = cc._decorator;

// 自定义类
@ccclass("cannon_bullet_skin")
class cannon_bullet_skin {
    @property(cc.SpriteFrame)   // 子弹精灵图片
    public cannon_bullet_icon: cc.SpriteFrame = null;

    @property(cc.Integer)
    public bullet_effect_sample: number = 8;    // 子弹效果每帧持续时间
}

@ccclass
export class CannonBullet extends cc.Component {

    @property(cc.Integer)   // 子弹移动速度
    public speed: number = 200;

    @property(cc.Integer)   // 子弹攻击力
    public attack: number = 10;

    @property(cc.Integer)   // 子弹爆炸范围
    public bomb_r: number = 30;

    @property(cc.Integer)  // 子弹等级
    public bullet_level: number = 1;

    @property(cc.Node)          // 子弹精灵节点
    public anim_node: cc.Node = null;

    @property(cc.SpriteFrame)   // 子弹效果资源
    public bullet_effect_anim: Array<cc.SpriteFrame> = [];

    @property({
        type: cannon_bullet_skin,
    })
    public level_bullet_skin = [];   // 每个等级子弹皮肤

    public bullet_root_node: cc.Node = null;    // 子弹存放节点
    public shoot_enemy: cc.Node = null;         // 敌人

    public cannon_bullet_frame_anim: FrameAnim = null;    // 保存自定义动画组件

    onLoad() {
        this.bullet_root_node = cc.find('Canvas/tower_panel/bullet_root');
        this._set_bullet_skin_by_level();

        // 绑定自定义动画组件
        this.cannon_bullet_frame_anim = this.anim_node.addComponent(FrameAnim);
        this.cannon_bullet_frame_anim.sprite_com = this.anim_node.getComponent(cc.Sprite);
        this.cannon_bullet_frame_anim.anim_com = this.anim_node.getComponent(cc.Animation);
    }

    // 设置炮弹皮肤
    private _set_bullet_skin_by_level(): void {
        this.anim_node.getComponent(cc.Sprite).spriteFrame = this.level_bullet_skin[this.bullet_level - 1].cannon_bullet_icon;
    }

    // 子弹射击
    public shoot(level: number, bullet_world_pos: cc.Vec2, enemy_world_pos: cc.Vec2, enemy: cc.Node): void {
        // 子弹参数
        this.bullet_level = level;
        this.speed = CannonBulletParams[this.bullet_level - 1].speed;
        this.attack = CannonBulletParams[this.bullet_level - 1].attack;
        this.bomb_r = CannonBulletParams[this.bullet_level - 1].bomb_r;
        this.shoot_enemy = enemy;

        this._set_bullet_skin_by_level();

        // 把敌人，转换成和子弹同一个坐标系下
        let start_pos: cc.Vec2 = this.bullet_root_node.parent.convertToNodeSpaceAR(bullet_world_pos);
        let end_pos: cc.Vec2 = this.bullet_root_node.parent.convertToNodeSpaceAR(enemy_world_pos);

        // 调整位置
        this.node.setPosition(start_pos);
        // this.anim_node.angle = 0;

        // 贝塞尔曲线的方式移动子弹
        let dir: cc.Vec2 = enemy_world_pos.sub(bullet_world_pos);   // 移动方向
        let len: number = dir.mag();                    // 向量差长度
        let time: number = len / this.speed;            // 求运动时间

        if (this.shoot_enemy) {
            let enemy_com: Enemy = this.shoot_enemy.getComponent(Enemy);
            end_pos = enemy_com.walk_pos_by_time(time);
        }

        // cocos中bezierTo是三阶贝塞尔 两个控制点,起点,终点
        let ctrl: cc.Vec2 = cc.v2();
        // 取中点做控制点,垂直方向y在起点和终点中取较大值
        ctrl.x = (start_pos.x + end_pos.x) * 0.5;     // 水平方向取中点值
        ctrl.y = (end_pos.y > start_pos.y) ? end_pos.y : start_pos.y;   // 垂直方向取较大值
        ctrl.y += 40;   // 垂直方向拉高弧度

        // 执行贝塞尔运动
        let time_offset: number = 0.2;      // 时间补偿
        cc.tween(this.node)
            .bezierTo(time + time_offset, ctrl, ctrl, end_pos)
            .call(() => {
                // 执行爆炸动画、伤害计算
                this._on_bullet_boom();
                // 炮弹效果
                this._bullet_boom_anim();
            })
            .start();

        // 贝塞尔运动得同时调整炮弹角度
        let degree: number = 0;
        // 判断炮弹是往左还是往右
        degree = (end_pos.x < start_pos.x) ? (180 - Math.random() * 10) : (-180 + Math.random() * 10);
        cc.tween(this.anim_node)
            .by(time + time_offset - 0.05, { angle: degree })
            .start();
    }

    // 爆炸动画
    private _bullet_boom_anim(): void {
        // 还原
        this.anim_node.angle = 0;
        this.cannon_bullet_frame_anim.sprite_frame_arr = this.bullet_effect_anim;
        this.cannon_bullet_frame_anim.sample = this.level_bullet_skin[this.bullet_level - 1].bullet_effect_sample;

        // 播放一次爆炸动画
        this.cannon_bullet_frame_anim.play_once(() => {
            // cc.log('子弹爆炸结束');
            // 移除子弹
            this.node.destroy();
        });
    }

    // 炮弹伤害 --> 范围伤害
    private _on_bullet_boom(): void {
        const bomb_r: number = this.bomb_r;
        let bomb_pos: cc.Vec2 = this.node.getPosition();

        let enemy_arr: Array<cc.Node> = UG.get_enemy_arr();
        for (let i = 0; i < enemy_arr.length; i++) {
            // 判断敌人是否处于爆炸范围内
            let _enemy_pos: cc.Vec2 = enemy_arr[i].getPosition();
            let range: number = bomb_pos.sub(_enemy_pos).mag();
            if (range <= bomb_r) {
                let enemy_com: Enemy = enemy_arr[i].getComponent(Enemy);
                enemy_com.on_cannon_attacked(CannonBulletParams[this.bullet_level - 1].attack);
            }
        }
    }
}
